<?php

/**
 *	Tag paser class
 *
 *	@author Alexey A. Frolov <frolov.alexey@gmail.com>
 *	@package Tiger.Utils
 *	@version 0.2 04.07.2009
 */
class TTagParser
{
	/**
	 * @access protected
	 * @var string start tag
	 */
	protected $startTag = '<tgr:';
	
	/**
	 * @access protected
	 * @var string close tag
	 */
	protected $closeTag = '</tgr:';
	
	/**
	 * @access protected
	 * @var string end tag
	 */
	protected $endTag = '>';
	
	/**
	 * @access protected
	 * @var string content
	 */
	protected $content;
	
	/**
	 * @access protected
	 * @var integer current position
	 */
	protected $position = 0;
	
	/**
	 * @access protected
	 * @var string start tag callback
	 */
	protected $callbackStart = false;
	
	/**
	 * @access protected
	 * @var string start tag callback
	 */
	protected $callbackEnd = false;
	
	/**
	 * constructor
	 * 
	 * @access public
	 * @param string $content
	 */
	public function __construct($content = false)
	{
		if ($content) $this->content = $content;
	}
	
	/**
	 * set content
	 * 
	 * @access public
	 * @param string $content
	 */
	public function setContent($content = false)
	{
		if ($content) $this->content = $content;
	}
	
	public function setCallbacks($start, $end)
	{
		$this->callbackStart	= $start;
		$this->callbackEnd		= $end;
	}
	
	/**
	 * find next tag
	 * 
	 * @access protected
	 * @return string content tag
	 */
	protected function getNextTag()
	{
		if ($this->position >= strlen($this->content)) return false;

		$elementBegin = $this->position = strpos($this->content, $this->startTag, $this->position);
		if ($this->position === false) return false;
		$elementEnd = $this->position = strpos($this->content, $this->endTag, $this->position);
		$this->position += strlen($elementEnd);
		
		return substr($this->content, $elementBegin + strlen($this->startTag), $elementEnd - ($elementBegin + strlen($this->startTag)) );
	}

	/**
	 * find next closed tag
	 * 
	 * @access protected
	 * @param string $name
	 * @return integer position close tag
	 */
	protected function getCloseTag($name)
	{
		$elementBegin = $this->position = strpos($this->content, $this->closeTag . $name, $this->position);
		if ($this->position === false) return false;
		$elementEnd = $this->position = strpos($this->content, $this->endTag, $this->position);
		$this->position += strlen($elementEnd);
		
		return $elementBegin;
	}
	
	/**
	 * parse tag
	 * 
	 * @access protected
	 * @param string $string
	 * @return array tag information
	 */
	protected function parseTag($string)
	{
		$string = trim($string);
		
		$tag = array();
		if ($string[strlen($string) - 1] == '/')
		{
			$tag['is_short'] = true;
			$string = substr($string, 0, strlen($string) - 1);
		}
		else
		{
			$tag['is_short'] = false;
		}
		$attributes = explode(' ', $string);

		$tag['name'] = array_shift($attributes);
		$tag['attributes'] = array();
		foreach ($attributes as $v)
		{
			if (!trim($v)) continue;
			
			$attr = explode('=', trim($v));
			$tag['attributes'][trim($attr[0])] = trim($attr[1]);
		}
		
		return $tag;
	}
	
	/**
	 * parse content
	 * 
	 * @access public
	 */
	public function parse()
	{
		while ($s = $this->getNextTag())
		{
			$tag = ($this->parseTag($s));
			if ($this->callbackStart) call_user_function($this->callbackStart, $tag, $this->position);
			
			if (!$tag['is_short'])
			{
				$b = $this->position;
				$end = ($this->getCloseTag($tag['name']));
				
				if ($this->callbackEnd) call_user_function($this->callbackEnd, substr($this->content, $b, $end - $b), $b, $end - $b);
			}
		}
	}
}

?>